﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
using System.Xml;
using System.Threading;
using System.Net.Mail;
using System.Reflection;

namespace ARelogRelog
{
    public partial class Form1 : Form
    {
        bool _running = false;
        List<ARelog> _listCurrentARelog = new List<ARelog>();
        List<InactivityWatcher> _listInactivityWatcher = new List<InactivityWatcher>();

        log4net.ILog _logger = log4net.LogManager.GetLogger(typeof(Form1));

        public Form1()
        {
            InitializeComponent();
        }

        private void buttonAdd_Click(object sender, EventArgs e)
        {
            OpenFileDialog d = new OpenFileDialog();
            d.Filter = "ARelog Application|ARelog.exe";
            d.InitialDirectory = Application.StartupPath;

            if (d.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Config.AddARelogPath(d.FileName);
            }

            ReloadARelogList();
        }

        void ReloadARelogList()
        {
            listBoxARelog.Items.Clear();

            foreach (ARelog pARelog in Config.ARelogs)
            {
                listBoxARelog.Items.Add(pARelog.FileName);
            }

            buttonRun.Enabled = listBoxARelog.Items.Count >= 1;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Stream cs = Assembly.GetAssembly(typeof(Form1)).GetManifestResourceStream("ARelogRelog.log4net.config");
            log4net.Config.XmlConfigurator.Configure(cs);
            ReloadARelogList();
        }

        private void buttonRemove_Click(object sender, EventArgs e)
        {
            if (listBoxARelog.SelectedIndex >= 0)
            {
                Config.RemoveRelogPath(listBoxARelog.SelectedIndex);
                ReloadARelogList();
            }
        }

        private void buttonRun_Click(object sender, EventArgs e)
        {
            if (_running)
            {
                Log("STOP");
                ChangeEnabled(true);
                timerMain.Stop();
                timerBlizzardError.Stop();

                CloseCurrentARelogs();
                _running = false;
                buttonRun.Text = "RUN";
            }
            else
            {
                Log("START");
                ChangeEnabled(false);
                timerMain.Start();
                timerBlizzardError.Start();
                _running = true;
                buttonRun.Text = "STOP";
                Tick();
            }
        }

        void ChangeEnabled(bool enable)
        {
            listBoxARelog.Enabled = enable;
            buttonAdd.Enabled = enable;
            buttonRemove.Enabled = enable;
            buttonConfig.Enabled = enable;
        }

        private void timerMain_Tick(object sender, EventArgs e)
        {
            timerMain.Enabled = false;

            Tick();

            timerMain.Enabled = true;
        }

        void Tick()
        {
            try
            {
                foreach (ARelog pARelog in Config.ARelogs)
                {
                    if (pARelog.ShouldRun && !Utils.IsRunning(pARelog))
                        StartARelog(pARelog);
                    else if (!pARelog.ShouldRun && Utils.IsRunning(pARelog))
                        CloseARelog(pARelog);
                }
            }
            catch (Exception ex)
            {
                _logger.Error("Error in tick", ex);
                throw;
            }
        }

        void CloseCurrentARelogs()
        {
            foreach (ARelog pARelog in _listCurrentARelog)
            {
                Log("Closing ARelog and all depending applications: " + pARelog.FileName);
                Utils.CloseARelogDependingProcesses(pARelog);
            }

            foreach (InactivityWatcher pWatcher in _listInactivityWatcher)
            {
                pWatcher.StopWatcher();
            }

            _listCurrentARelog.Clear();
        }

        void CloseARelog(ARelog pARelog)
        {
            Log("Closing ARelog and all depending applications: " + pARelog.FileName);

            Utils.CloseARelogDependingProcesses(pARelog);

            foreach (InactivityWatcher pWatcher in _listInactivityWatcher)
            {
                
            }

            for (int i = 0; i < _listInactivityWatcher.Count; i++)
            {
                if (_listInactivityWatcher[i].ARelog.FileName == pARelog.FileName)
                {
                    _listInactivityWatcher[i].StopWatcher();
                    _listInactivityWatcher.RemoveAt(i);
                }
            }

            for (int i = 0; i < _listCurrentARelog.Count; i++)
            {
                if (_listCurrentARelog[i].FileName == pARelog.FileName)
                    _listCurrentARelog.RemoveAt(i);
            }

        }

        void StartARelog(ARelog pARelog)
        {
            _listCurrentARelog.Add(pARelog);

            Log(string.Format("Starting ARelog: {0}", pARelog.FileName));

            Utils.CloseARelogDependingProcesses(pARelog);
            Thread.Sleep(5000);
            Utils.RunARelog(pARelog.FileName);

            // close bot if it is inactive for at least 5 minutes
            InactivityWatcher pInactivityWatcher = new InactivityWatcher(pARelog, 60000, 5);

            foreach (ARelogMonitor pMonitor in pInactivityWatcher.ARelog.Monitors)
            {
                if (pMonitor.Enabled)
                {
                    Log(string.Format("Watching for inactivity: {0}", pMonitor.BuddyPath));
                }
            }

            pInactivityWatcher.Warning += (s, e) =>
                {
                    try
                    {
                        Log(string.Format("Demonbuddy [{0}] is inactive since {1} ... closing", e.Monitor.BuddyPath, e.LastActivity.ToString()));
                        Utils.CloseProcessByExeFileName(e.Monitor.GamePath);
                        Utils.CloseProcessByExeFileName(e.Monitor.BuddyPath);
                        Thread.Sleep(500);
                    }
                    catch (Exception ex)
                    {
                        _logger.Error("Error while closing for inactivity", ex);
                        throw;
                    }
                };

            try
            {
                pInactivityWatcher.StartWatcher();
            }
            catch (Exception ex)
            {
                _logger.Error("Error while starting inactivity watcher for ARelog", ex);
                throw;
            }

            _listInactivityWatcher.Add(pInactivityWatcher);
        }

        void Log(string s)
        {
            if (textBoxLog.InvokeRequired)
            {
                SetLogCallback d = new SetLogCallback(Log);
                Invoke(d, new object[] { s });
            }
            else
            {
                textBoxLog.AppendText(Environment.NewLine);
                textBoxLog.AppendText(string.Format("[{0}] {1}", DateTime.Now.ToString(), s));
                _logger.Info(s);
            }
        }

        public delegate void SetLogCallback(string s);

        private void timerBlizzardError_Tick(object sender, EventArgs e)
        {
            try
            {
                timerBlizzardError.Enabled = false;
                Utils.CloseProcessByName("BlizzardError");
                timerBlizzardError.Enabled = true;
            }
            catch (Exception ex)
            {
                _logger.Error("Error while closing BlizzardError process", ex);
                throw;
            }
        }

        private void buttonConfig_Click(object sender, EventArgs e)
        {
            if (listBoxARelog.SelectedIndex > -1)
            {
                ARelog pARelog = new ARelog((string)listBoxARelog.SelectedItem);

                TimeConfigForm f = new TimeConfigForm();
                f.Initialize(pARelog);

                if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    pARelog.SetSchedules(f.Schedules);
            }
        }
    }
}
